﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using TeacherLeftHand.DataAccess;
using TeacherLeftHand.Model;
using System.Linq;
using TeacherLeftHand.Messages;
using TeacherLeftHand.Util;
using MessageBox = System.Windows.MessageBox;

namespace TeacherLeftHand.ViewModel
{
    public class KnowledgeItemListViewModel : ViewModelBase
    {
        #region constructor


        public KnowledgeItemListViewModel()
        {

            // initialize properties and private fields
            _kiAccessor = new KnowledgeItemAccessor();
            _maxTopicNo = _kiAccessor.GetMaxTopicNo();
            _subjectList = _kiAccessor.GetSubjectList();
            _subjectList.Insert(0, "");
            SelectedKnowledgeItem = new KnowledgeItem();
            //KIList = LoadAll();
            //RefreshPaging();

            //if (KIList.Count > 0)
            //{
            //    SelectedKnowledgeItem = KIList[0];
            //}

            SearchCondition = new KISearchCondition();

            // Commands

            // Message Registration

            //// filter KIList based on selected class level of teaching plan
            //Messenger.Default.Register<int>(this, "SelectedClassLevel", (classLevel) =>
            //                                                       {
            //                                                           SearchCondition.SelectedClassLevel = classLevel;
            //                                                           var list = _kiAccessor.Search(SearchCondition);
            //                                                           KIList.Clear();
            //                                                           foreach (var data in list)
            //                                                           {
            //                                                               KIList.Add(data as KnowledgeItem);
            //                                                           }
            //                                                       });

            //// filter KIList based on selected subject of teaching plan
            //Messenger.Default.Register<string>(this, "SelectedSubject", (selectedSubject) =>
            //                                                                {
            //                                                                    SearchCondition.Subject = selectedSubject;
            //                                                                    var list = _kiAccessor.Search(SearchCondition);
            //                                                                    KIList.Clear();
            //                                                                    foreach (var data in list)
            //                                                                    {
            //                                                                        KIList.Add(data as KnowledgeItem);
            //                                                                    }
            //                                                                });

            // update KIList when KI item are modified somewhere else

            Messenger.Default.Register<UpdateKIMessage>(this, UpdateKList);

            Messenger.Default.Register<KnowledgeItemFilterMessage>(this, Filter);
        }

        #endregion

        #region Properties

        /// <summary>
        /// The <see cref="IsLoaded" /> property's name.
        /// </summary>
        public const string IsLoadedPropertyName = "IsLoaded";

        private bool _isLoaded;

        /// <summary>
        /// Gets the IsLoaded property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool IsLoaded
        {
            get
            {
                return _isLoaded;
            }

            set
            {
                if (_isLoaded == value)
                {
                    return;
                }

                _isLoaded = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(IsLoadedPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="HasKIs" /> property's name.
        /// </summary>
        public const string HasKIsPropertyName = "HasKIs";

        /// <summary>
        /// Gets the HasKIs property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool HasKIs
        {
            get
            {
                if (SelectedKnowledgeItem == null) return false;
                if (SelectedKnowledgeItem.ID == -1) return false;
                return KIList.Count > 0;
            }
        }

        private int _maxTopicNo = 1;
        //private ObservableCollection<string> _topics;
        private KnowledgeItem _selectedKnowledgeItem = new KnowledgeItem();
        private ObservableCollection<KnowledgeItem> _kiList;
        private KISearchCondition _searchCondition;

        public KnowledgeItem SelectedKnowledgeItem
        {
            get
            {
                return _selectedKnowledgeItem;
            }
            set
            {
                _selectedKnowledgeItem = value;
                RaisePropertyChanged("SelectedKnowledgeItem");
                RaisePropertyChanged(HasKIsPropertyName);
            }
        }

        private ICommand _deleteCommand;
        public ICommand DeleteCommand
        {
            get
            {
                if (_deleteCommand == null)
                {
                    _deleteCommand = new RelayCommand(() =>
                    {
                        var result = MessageBox.Show(DataHelper.DeleteConfirmationMessage,
                                      DataHelper.DeleteConfirmationCaption,
                                      MessageBoxButton.OKCancel, MessageBoxImage.Warning);
                        if (result == MessageBoxResult.Cancel) return;
                        var msg = new UpdateKIMessage
                        {
                            Action = UpdateAction.Delete,
                            KnowledgeItem = SelectedKnowledgeItem
                        };
                        Messenger.Default.Send(msg);
                    });

                }
                return _deleteCommand;
            }

        }

        private ICommand _createCommand;
        public ICommand CreateCommand
        {
            get
            {
                if (_createCommand == null)
                {
                    _createCommand = new RelayCommand(Create);
                }
                return _createCommand;
            }

        }

        private ICommand _editCommand;
        public ICommand EditCommand
        {
            get
            {
                if (_editCommand == null)
                {
                    _editCommand = new RelayCommand(() => Update(SelectedKnowledgeItem));
                }
                return _editCommand;
            }
        }


        public ObservableCollection<KnowledgeItem> KIList
        {
            get
            {
                return _kiList;
            }
            set
            {
                _kiList = value;
                RaisePropertyChanged("KIList");

            }
        }



        private ICommand _searchCommand;
        public ICommand SearchCommand
        {
            get
            {
                if (_searchCommand == null)
                {
                    _searchCommand = new RelayCommand(() =>
                                                          {
                                                              //if (!SearchCondition.AdvancedSearchMode)
                                                              //{
                                                              //    string keyword = SearchCondition.Keyword + "";
                                                              //    SearchCondition = new KISearchCondition { Keyword = keyword };
                                                              //}

                                                              var result = new ObservableCollection<KnowledgeItem>();
                                                              var worker = new BackgroundWorker();
                                                              worker.DoWork += (s, oe) =>
                                                              {
                                                                  if (SearchCondition.AdvancedSearchMode)
                                                                  {
                                                                      result = AdvanceSearch(SearchCondition);
                                                                  }
                                                                  else
                                                                  {
                                                                      result = Search(SearchCondition);
                                                                  }
                                                              };
                                                              worker.RunWorkerCompleted += (s, oe) =>
                                                              {
                                                                  _kiList = result;
                                                                  if (_kiList.Count == 0)
                                                                  {
                                                                      LoadAll();
                                                                      RaisePropertyChanged(HasKIsPropertyName);
                                                                  }
                                                                  else
                                                                  {
                                                                      SelectedKnowledgeItem = _kiList.Count > 0
                                                                                                  ? _kiList[0]
                                                                                                  : null;
                                                                      RefreshPaging();
                                                                      RaisePropertyChanged("KIList");
                                                                      RaisePropertyChanged(HasKIsPropertyName);
                                                                  }
                                                              };
                                                              worker.RunWorkerAsync();
                                                          });
                }
                return _searchCommand;
            }
        }

        public KISearchCondition SearchCondition
        {
            get { return _searchCondition; }
            set
            {
                if (_searchCondition != value)
                {
                    _searchCondition = value;
                    RaisePropertyChanged("SearchCondition");
                }
            }
        }

        /// <summary>
        /// The <see cref="IsLoading" /> property's name.
        /// </summary>
        public const string IsLoadingPropertyName = "IsLoading";

        private bool _isLoading;

        /// <summary>
        /// Gets the IsLoading property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public bool IsLoading
        {
            get
            {
                return _isLoading;
            }

            set
            {
                if (_isLoading == value)
                {
                    return;
                }

                _isLoading = value;
                // Update bindings, no broadcast
                RaisePropertyChanged(IsLoadingPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SubjectList" /> property's name.
        /// </summary>
        public const string SubjectListPropertyName = "SubjectList";

        private ObservableCollection<string> _subjectList = new ObservableCollection<string>();

        /// <summary>
        /// Gets the SubjectList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<string> SubjectList
        {
            get
            {
                return _subjectList;
            }

            set
            {
                if (_subjectList == value)
                {
                    return;
                }

                _subjectList = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(SubjectListPropertyName);
            }
        }

        /// <summary>
        /// Gets the TopicList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public int MaxTopic
        {
            get
            {
                return _maxTopicNo;
            }
        }

        private ObservableCollection<int> _classLevelList = DataHelper.ClassLevelList;

        /// <summary>
        /// Gets the ClassLevelList property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public int MaxClassLevel
        {
            get
            {
                return _classLevelList.Last();
            }
        }
        #endregion

        #region Members

        private readonly KnowledgeItemAccessor _kiAccessor;
        #endregion

        #region PAGING ***********************************************************************************
        private int _currentPage = 1;
        private int _totalPages = 1;
        const int RECORDS_PER_PAGE = 10;
        private enum PagingMode { Next = 2, Previous = 3, First = 1, Last = 4 };
        private ObservableCollection<KnowledgeItem> _pagedKIList = new ObservableCollection<KnowledgeItem>();
        public ObservableCollection<KnowledgeItem> PagedKIList
        {
            get
            {
                return _pagedKIList;
            }
            set
            {
                _pagedKIList = value;
                RaisePropertyChanged("PagedKIList");
            }
        }

        private ICommand _firstPageCommand;
        public ICommand FirstPageCommand
        {
            get
            {
                if (_firstPageCommand == null)
                {
                    _firstPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.First), () => _currentPage > 1);
                }
                return _firstPageCommand;
            }

        }

        private ICommand _prevPageCommand;
        public ICommand PrevPageCommand
        {
            get
            {
                if (_prevPageCommand == null)
                {
                    _prevPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.Previous), () => _currentPage > 1);
                }

                return _prevPageCommand;
            }
        }

        private ICommand _nextPageCommand;
        public ICommand NextPageCommand
        {
            get
            {
                if (_nextPageCommand == null)
                {
                    _nextPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.Next), () => _currentPage < _totalPages);
                }
                return _nextPageCommand;
            }
        }

        private ICommand _lastPageCommand;
        public ICommand LastPageCommand
        {
            get
            {
                if (_lastPageCommand == null)
                {
                    _lastPageCommand = new RelayCommand(() => CustomPaging((int)PagingMode.Last), () => _currentPage < _totalPages);
                }

                return _lastPageCommand;
            }
        }

        private ICommand _pageChanged;
        public ICommand PageChanged
        {
            get
            {
                if (_pageChanged == null)
                {
                    _pageChanged = new RelayCommand<string>(text =>
                    {
                        try
                        {
                            var temp = int.Parse(text);
                            if (temp > 0 && temp <= TotalPages)
                            {
                                CurrentPage = temp;
                                RefreshPaging();
                            }
                            else
                            {
                                CurrentPage = _currentPage;
                            }
                        }
                        catch (FormatException)
                        {
                            CurrentPage = _currentPage;
                        }
                    });
                }
                return _pageChanged;
            }
        }
        private void CustomPaging(int mode)
        {

            switch (mode)
            {
                case (int)PagingMode.Next:
                    //if (_kiList.Count > (_currentPage * RECORDS_PER_PAGE))
                    //{
                    //    _pagedKIList.Clear();

                    //    if (_kiList.Count >= ((_currentPage * RECORDS_PER_PAGE) + RECORDS_PER_PAGE))
                    //    {
                    //        for (int i = _currentPage * RECORDS_PER_PAGE; i < ((_currentPage * RECORDS_PER_PAGE) + RECORDS_PER_PAGE); i++)
                    //        {
                    //            _pagedKIList.Add(KIList[i]);
                    //        }
                    //    }
                    //    else
                    //    {
                    //        for (int i = _currentPage * RECORDS_PER_PAGE; i < KIList.Count; i++)
                    //        {
                    //            _pagedKIList.Add(KIList[i]);
                    //        }
                    //    }

                    //    CurrentPage++;
                    //}
                    if (CurrentPage < TotalPages)
                    {
                        CurrentPage++;
                    }
                    break;
                case (int)PagingMode.Previous:
                    //if (_currentPage > 1)
                    //{
                    //    _pagedKIList.Clear();
                    //    CurrentPage--;
                    //    for (int i = ((_currentPage * RECORDS_PER_PAGE) - RECORDS_PER_PAGE); i < (_currentPage * RECORDS_PER_PAGE); i++)
                    //    {
                    //        _pagedKIList.Add(_kiList[i]);
                    //    }

                    //}
                    if (CurrentPage > 1)
                    {
                        CurrentPage--;
                    }
                    break;
                case (int)PagingMode.First:
                    //CurrentPage = 2;
                    //CustomPaging((int)PagingMode.Previous);
                    if (TotalPages > 0)
                    {
                        CurrentPage = 1;
                    }
                    break;
                case (int)PagingMode.Last:
                    //CurrentPage = _totalPages - 1;
                    //CustomPaging((int)PagingMode.Next);
                    if (TotalPages > 0)
                    {
                        CurrentPage = TotalPages;
                    }
                    break;
            }
            RefreshPaging();
        }

        private void RefreshPaging()
        {

            try
            {
                _pagedKIList.Clear();
                if (_kiList.Count > 0)
                {
                    TotalPages = (_kiList.Count % RECORDS_PER_PAGE == 0) ? _kiList.Count / RECORDS_PER_PAGE : _kiList.Count / RECORDS_PER_PAGE + 1;
                    CurrentPage = _currentPage < _totalPages ? _currentPage : _totalPages;
                    if (_currentPage == 0)
                    {
                        CurrentPage = 1;
                    }
                    if (_kiList.Count >= _currentPage * RECORDS_PER_PAGE)
                    {
                        for (int i = (_currentPage - 1) * RECORDS_PER_PAGE; i < _currentPage * RECORDS_PER_PAGE; i++)
                        {
                            _pagedKIList.Add(_kiList[i]);
                        }
                    }
                    else
                    {
                        for (int i = (_currentPage - 1) * RECORDS_PER_PAGE; i < _kiList.Count; i++)
                        {
                            _pagedKIList.Add(_kiList[i]);
                        }
                    }
                }
                else
                {
                    TotalPages = 1;
                    CurrentPage = 1;
                }
                //try
                //{
                //if (_kiList.Count > 0)
                //{
                //    if(_currentPage>0)
                //    {
                //        _currentPage--;
                //    }

                //    CustomPaging((int)PagingMode.Next);
                //}
                //else
                //{
                //    CurrentPage = 0;
                //}
                //else
                //{
                //    MessageBox.Show("No Records Exists for the selected category");
                //}
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        public int CurrentPage
        {
            get
            {
                return _currentPage;
            }
            set
            {
                _currentPage = value;
                RaisePropertyChanged("CurrentPage");
            }
        }

        public int TotalPages
        {
            get
            {
                return _totalPages;
            }
            set
            {
                _totalPages = value;
                RaisePropertyChanged("TotalPages");
            }
        }
        #endregion paging

        #region Methods

        private void Create()
        {
            ViewModelLocator.CreateCreateNewKI();
            Messenger.Default.Send(new CreateNewKIWindowMessage { Action = WindowAction.OpenCreate });
        }

        private void Update(KnowledgeItem item)
        {
            ViewModelLocator.CreateCreateNewKI();
            //Messenger.Default.Send(item, "Update");
            Messenger.Default.Send(new CreateNewKIWindowMessage { Action = WindowAction.OpenUpdate, Item = item });
        }

        private void UpdateKList(UpdateKIMessage msg)
        {
            switch (msg.Action)
            {
                case UpdateAction.Add:
                    {
                        if (KIList == null) break;
                        
                        if (IsLoaded)
                        {
                            KIList.Add(msg.KnowledgeItem);
                            SelectedKnowledgeItem = KIList[0];
                            RefreshPaging();
                            RaisePropertyChanged("KIList");
                            RaisePropertyChanged(HasKIsPropertyName);
                        }
                    }
                    break;
                case UpdateAction.Update:
                    {
                        if (KIList == null) break;
                        if (KIList.Count <= 0) break;
                        var index = KIList.IndexOf(KIList.Where(x => x.ID == msg.KnowledgeItem.ID).Select(x => x).FirstOrDefault());
                        if (index >= 0)
                        {
                            KIList[index] = new KnowledgeItem(msg.KnowledgeItem);
                            RefreshPaging();
                            RaisePropertyChanged("KIList");
                            RaisePropertyChanged(HasKIsPropertyName);
                        }
                    }
                    break;
                case UpdateAction.Delete:
                    {
                        if (KIList == null) break;
                        if (KIList.Count <= 0) break;
                        var index = KIList.IndexOf(KIList.Where(x => x.ID == msg.KnowledgeItem.ID).Select(x => x).FirstOrDefault());
                        if (index >= 0)
                        {
                            KIList.RemoveAt(index);
                            SelectedKnowledgeItem = KIList.Count > 0 ? KIList.First() : new KnowledgeItem();
                            RefreshPaging();
                            RaisePropertyChanged("KIList");
                            RaisePropertyChanged(HasKIsPropertyName);
                        }
                    }
                    break;
                default:
                    { throw new NotSupportedException("Unknown action"); }
            }
            
        }

        private void Filter(KnowledgeItemFilterMessage msg)
        {

            var worker = new BackgroundWorker();
            var result = new ObservableCollection<KnowledgeItem>();
            worker.DoWork += (s, e) =>
                                 {
                                     if (!IsLoaded)
                                     {
                                         _isLoaded = true;
                                     }
                                     var filterInfo = new KISearchCondition
                                                          {
                                                              SelectedClassLevel = msg.ClassLevel,
                                                              Subject = msg.Subject,
                                                              MinTopicNo = msg.TopicNo
                                                          };
                                     result = AdvanceSearch(filterInfo);
                                 };
            worker.RunWorkerCompleted += (s, e) =>
                                    {
                                        KIList = result;
                                        RefreshPaging();
                                        RaisePropertyChanged("KIList");
                                        RaisePropertyChanged(IsLoadedPropertyName);
                                        IsLoading = false;
                                    };

            IsLoading = true;
            worker.RunWorkerAsync();
        }

        public ObservableCollection<KnowledgeItem> Search(KISearchCondition searchCondition)
        {
            return _kiAccessor.Search(searchCondition);
        }

        public ObservableCollection<KnowledgeItem> AdvanceSearch(KISearchCondition searchCondition)
        {
            return _kiAccessor.AdvanceSearch(searchCondition);
        }

        public bool Delete(KnowledgeItem item)
        {
            return _kiAccessor.Delete(item);
        }

        private void LoadAll()
        {
            var worker = new BackgroundWorker();
            var result = new ObservableCollection<KnowledgeItem>();
            worker.DoWork += (s, oe) =>
                                 {
                                     result = _kiAccessor.GetAll();
                                 };
            worker.RunWorkerCompleted += (s, oe) =>
                                             {
                                                 _kiList = result;
                                                 RefreshPaging();
                                                 RaisePropertyChanged("KIList");
                                                 IsLoading = false;
                                             };
            IsLoading = true;
            worker.RunWorkerAsync();
        }
        #endregion

    }
}
